#include "wm_include.h"
#include "fifo.h"
#include "string.h"

_fifo_str fifo_str;

int FifoInit(uint8_t *fifo_addr, uint32_t fifo_size)
{
	_fifo_str *p = &fifo_str;
	
	if(fifo_addr == NULL || fifo_size < 2048)
		return -1;

	memset((char *)p, 0, sizeof(_fifo_str));
	p->buf = fifo_addr;
    p->in = 0;
    p->out = 0;
	fifo_size = fifo_size / 2 * 2;
    p->size = fifo_size;// - TRANTISION_BUFF_SIZE;
	return 0;
}

int FifoDataLen(void)
{
	_fifo_str *p = &fifo_str;
#if 0
    if((p->in - p->out) > p->size)
    {
        p->out = p->in - p->size;
    }
#else
	if (p->in < p->out)
	{
		return (p->size - p->out + p->in);
	}
#endif
	
	return (p->in - p->out);
}

int FifoSpaceLen(void)
{
	_fifo_str *p = &fifo_str;
	
	return (p->size - (p->in - p->out));
}

int FifoRead(uint8_t *buf, uint32_t len)
{
	uint32_t i = 0, j = 0;
	_fifo_str *p = &fifo_str;
	//wm_printf("p->out:%d,%d, %d\r\n", p->out, p->in, p->size);
	j = (p->out % p->size);
	if (p->in > p->out)
	{
		len = min(len, p->in - p->out);
	}
	else
	{
		len = min(len, p->in + p->size - p->out);
	}
	i = min(len, p->size - j);
	memcpy(buf, p->buf + j, i);
	memcpy(buf + i, p->buf, len - i);
	p->out = (p->out + len) % p->size;
	return len;
}

static void FifoTrantisionBuffWrite(uint32_t len)
{
	uint32_t copy_len=0, i=0;
	_fifo_str *p = &fifo_str;

	i = p->in % p->size;
//	if(i >= 0 && i < TRANTISION_BUFF_SIZE)
	if(i < TRANTISION_BUFF_SIZE)
	{
		if(TRANTISION_BUFF_SIZE - i >= len)
			copy_len = len;
		else
			copy_len = TRANTISION_BUFF_SIZE - i;

		memcpy(p->buf + p->size + i, p->buf + i, copy_len);
	}
}

int FifoWrite(uint8_t *buf, uint32_t len)
{
	uint32_t i = 0, j = 0;
	_fifo_str *p = &fifo_str;

	j = p->in % p->size;
//	len = min(len, p->size - p->in + p->out);
	i = min(len, p->size - j);
	memcpy(p->buf + j, buf, i);
	memcpy(p->buf, buf + i, len - i);
	
	//FifoTrantisionBuffWrite(len);
	p->in = (p->in + len)%p->size;

	return len;
}

void FifoClear(void)
{
	_fifo_str *p = &fifo_str;
	
    p->in = 0;
    p->out = 0;
}

int FifoGetRemainLen(void)
{
	uint32_t i = 0, j = 0;
	_fifo_str *p = &fifo_str;

	i = p->out % p->size;
	j = p->in % p->size;

	if(i > j)
		return (p->size + p->in - p->out);
	else
		return p->in - p->out;
}

void FifoRemoveData(uint32_t len)
{
	uint32_t i = 0;
	_fifo_str *p = &fifo_str;

	i = p->in - p->out;
	i = min(i, len);

	p->out += i;
}

u8 * FifoGetCurTail(void)
{
	_fifo_str *p = &fifo_str;
	int i = (p->out % p->size);

	return p->buf + i;
}

